package cn.hongxin.sap.conn.task;

import cn.hongxin.basic.business.client.erp.BaErpFunctionClient;
import cn.hongxin.sap.conn.entity.ErpFunctionReturnVO;
import cn.hongxin.sap.conn.entity.ParamEntity;
import cn.hongxin.sap.conn.utils.MultiFromSAP;
import cn.hongxin.sap.conn.utils.SapCommHelp;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Component
@EnableScheduling
@EnableAsync
public class ScheduledTasks {
    private static Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);

    @Autowired
    private SapCommHelp commHelp;

    @Autowired
    private BaErpFunctionClient baErpFunctionClient;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 解决Redis乱码问题
     * @param redisTemplate
     */
    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        // redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        //redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }

//    @Async
//    @Scheduled(cron = "0 */5 * * * ?")
    public void executeTask(){

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String updateIsexec = "";//更新isexec的状态，以便当前任务没执行完，下一个任务开始时查到isexec的值还是为0
        String sql = "select * from ba_erp_prod_queue where isexec='0'";
        //List<Map<String, Object>> maps = commHelp.queryList(sql);
        List<Map<String, Object>> maps = null;
        Object data = baErpFunctionClient.executeSelectSql(sql).getData();
        if(data!=null){
            maps = (List<Map<String, Object>>)data;
        }
        MultiFromSAP multiFromSAP = new MultiFromSAP();
        StringBuffer sbUpdate = new StringBuffer();
        try{

            if(maps!=null&&maps.size()>0){
                logger.info(sdf.format(new Date())+":共有:"+maps.size()+"条队列参数待执行!");
                boolean flag = true;
                for(Map<String,Object> map:maps){
                    if(flag){
                        for(int a = 0; a < maps.size(); a++){
                            sbUpdate.append(maps.get(a).get("id")+",");
                        }
                        //更新本次定时任务所有的参数记录的状态值，防止此线程5分钟未执行完，下一个定时任务又开始导致某个参数调用多次
                        updateIsexec=String.format(" update ba_erp_prod_queue set isexec=%1$s where id in (%2$s) ", "1",sbUpdate.substring(0,sbUpdate.length()-1));
                        sbUpdate.delete(0,sbUpdate.length());
                        //这里的更新为了防止当前任务没有执行完，下一个任务又开始了，然后查到对应的isexec的值还是0
                        //commHelp.insert(updateIsexec);//接口调用执行前先将isexec的值更新为1，标识该记录已被执行，接口调用完成后再更新一次该值
                        baErpFunctionClient.executeUpdateSql(updateIsexec);
                        flag = false;
                    }
                    ParamEntity paramEntity = multiFromSAP.getParamEntity(map.get("functionid") + "", baErpFunctionClient, redisTemplate);
                    ErpFunctionReturnVO returnVO = multiFromSAP.callSapRfc( map.get("functionid")+"", map.get("requestjson") + "", commHelp,paramEntity,baErpFunctionClient,redisTemplate);
                    if(StringUtils.isNotBlank(returnVO.getType())&&"N".equals(returnVO.getType())){
                        //type为N代表映射表存在数据，将对应参数队列记录恢复为未执行状态
                        logger.info(map.get("id")+":参数队列对应的映射表存在记录！");
                        updateIsexec = String.format(" update ba_erp_prod_queue set isexec='%1$s',responsejson='%2$s',updateTime=NOW() where id=%3$s ", "0","参数队列对应的映射表存在记录！",map.get("id"));
                        //commHelp.insert(updateIsexec);
                        baErpFunctionClient.executeUpdateSql(updateIsexec);
                    }else{//对应映射表不存在记录，接口才能调用成功，接口调用成功再更新队列参数表isexec的值为1（已执行）包括其他字段值
                        int result = commHelp.updateProdQueue(map.get("id") + "",returnVO,baErpFunctionClient);
                        if(result>0){
                            logger.info(sdf.format(new Date())+":定时轮询队列记录更新操作成功!");
                        }else{
                            logger.info(sdf.format(new Date())+":定时轮询队列记录更新操作失败!");
                        }
                    }
                }
            }else{
                logger.info(sdf.format(new Date())+":暂无可执行的队列参数!");
            }
        }catch (Exception e){
            logger.info(sdf.format(new Date())+":定时轮询队列记录操作出错!"+e.getMessage());
        }
    }

    //调用过账接口
//    @Async
//    @Scheduled(cron = "0 */30 * * * ?")
    public void executePosting(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        MultiFromSAP multiFromSAP = new MultiFromSAP();

        String queryTableName = "SELECT DISTINCT a.tablename,a.ba_erp_function_estruct_id, b.paramname,a.dataBaseName FROM ba_erp_function_estruct a"
                +" LEFT JOIN ba_erp_function_import b ON a.ba_erp_function_estruct_id = b.ba_erp_function_import_id WHERE"
                +" a.ba_erp_function_estruct_id IN ( SELECT id FROM ba_erp_function WHERE needcommit = 'Y' )";
        //List<Map<String, Object>> tableNames = commHelp.queryList(queryTableName);//查询过账接口所有对应的映射表
        List<Map<String, Object>> tableNames = null;//查询过账接口所有对应的映射表
        Object objQueryData = baErpFunctionClient.executeSelectSql(queryTableName).getData();
        if(objQueryData!=null){
            tableNames = (List<Map<String, Object>>)objQueryData;
        }
        StringBuffer insertSql = new StringBuffer();//SAP调用日志表插入对象
        //StringBuffer mappingTableSql = new StringBuffer();//映射表插入对象
        StringBuffer paramJsonStr = new StringBuffer();
        ErpFunctionReturnVO returnVO = null;
        try {
            if(tableNames!=null&&tableNames.size()>0){
                for(Map<String,Object> map:tableNames){
                    String tablename = map.get("tablename")+"";
                    String dataBaseName = map.get("databasename")+"";
                    String queryExport = "select * from "+tablename+" where type='' or type is null";
                    List<Map<String, Object>> insertList = commHelp.queryList(queryExport,dataBaseName);
                    if(insertList!=null&&insertList.size()>0){
                        for(Map<String,Object> inertStruct:insertList){
                            //mappingTableSql.delete(0,mappingTableSql.length());//清空原有内容
                            insertSql.delete(0,insertSql.length());//清空insertSql
                            paramJsonStr.delete(0,paramJsonStr.length());
                            String functionid = map.get("functionid")+"";
                            Object paramName = map.get("paramname");//paramname取至ba_erp_function_import表中的paramname
                            System.out.println(JSON.toJSONString(inertStruct));
                            paramJsonStr.append("{\""+paramName+"\":"+JSON.toJSONString(inertStruct)+"}");
                            ParamEntity paramEntity = multiFromSAP.getParamEntity(map.get("functionid") + "", baErpFunctionClient, redisTemplate);
                            returnVO = multiFromSAP.callSapRfc(functionid,paramJsonStr.toString(),commHelp,paramEntity,baErpFunctionClient,redisTemplate);
                            insertSql.append("insert into ba_erp_prod_queue(functionid, requestjson, responsejson, status, isexec,createtime, updatetime, operatetype)VALUES ");

                            String message = StringUtils.isNotBlank(returnVO.getReturnErr())?returnVO.getReturnErr():"成功";
                            insertSql.append(" ('"+functionid+"', '"+paramJsonStr+"', '"+message+"', 'true', '1',NOW(), NOW(), '过账接口调用' )");
                            Object objInsert = baErpFunctionClient.executeInsertSql(insertSql.toString()).getData();
                            int resultNum = (Integer)objInsert;
                            if(resultNum<0){//将调用过账接口返回的内容插入到参数队列表中，以日志方式存在
                                logger.info("参数队列表过账日志数据插入出错！执行语句："+insertSql.toString());
                            }

                           /* if(returnVO.getTablesMap()!=null&&returnVO.getTablesMap().size()>0){
                                for(String key:returnVO.getTablesMap().keySet()){
                                    List<Map<String, Object>> maps = returnVO.getTablesMap().get(key);//拿到返回的map结构信息
                                    String[] tableColunmName = maps.get(0).keySet().toArray(new String[maps.get(0).size()]);
                                    int count = commHelp.insertlfdjorder(maps.get(0).values().toArray(),tableColunmName,tablename,"add","");
                                    //mappingTableSql.append("insert into "+tablename+"("++") values "+);
                                     if(count<0){//将调用过账接口返回的内容更新到对应映射表中
                                         logger.info("映射表："+tablename+"更新出错！插入值："+maps.get(0).values());
                                     }
                                    break;//只执行一次，过账接口默认只有一个返回表结构
                                }
                            }*/
                        }
                    }else{
                        logger.info(sdf.format(new Date())+":暂无可执行的过账参数可调用!");
                    }
                }
            }
        }catch (Exception e){
            System.out.println("过账接口调用出错!堆栈信息："+e.getMessage());
            logger.info("过账接口调用出错!堆栈信息："+e.getMessage());
        }

    }

    @Bean
    public TaskScheduler taskScheduler(){
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        return taskScheduler;
    }

}
